#include "../include/common_lib.h"
#include "../include/ddr_common_func.h"
#include "../include/ddr_retention.h"

/*
/// data structure to store register address, value pairs
typedef struct Reg_Addr_Val {

  uint32_t Address; ///< register address
  uint16_t Value;   ///< register value
} Reg_Addr_Val_t;

/// enumeration of instructions for PhyInit Register Interface
typedef enum {
  saveRegs,         ///< save(read) tracked register values
  restoreRegs,      ///< restore (write) saved register values
} regInstr;
*/

/*! \def MAX_NUM_RET_REGS
 *  \brief default Max number of retention registers
 *
 * This define is only used by the PhyInit Register interface to define the max
 * amount of registered that can be saved. The user may increase this variable
 * as desired if a larger number of registers need to be restored.
*/
#define MAX_NUM_RET_REGS 5000

//int NumRegSaved = 934;    ///< Current Number of registers saved.
#define SRAM_E902_BASEADDR 0xFFE0170000
#define DDR_PHY_REG_SAVEADDR (SRAM_E902_BASEADDR)
Ddr_Reg_Config_t *ddr_Regu_Config = (Ddr_Reg_Config_t *)DDR_PHY_REG_SAVEADDR;

#ifndef ARRAY_SIZE
#define ARRAY_SIZE(x) (sizeof(x) / sizeof(x[0]))
#endif

static const uint64_t MiscRegList[] = {
    DFILPCFG0,
    ADDRMAP0,
    ADDRMAP1,
    ADDRMAP2,
    ADDRMAP3,
    ADDRMAP4,
    ADDRMAP5,
    ADDRMAP6,
    ADDRMAP7,
    ADDRMAP9,
    ADDRMAP10,
    ADDRMAP11,
};

static const uint32_t RetRegList_addr[934] =
{
    0x1005f,
    0x1015f,
    0x1105f,
    0x1115f,
    0x1205f,
    0x1215f,
    0x1305f,
    0x1315f,
    0x55,
    0x1055,
    0x2055,
    0x3055,
    0x4055,
    0x5055,
    0x200c5,
    0x2002e,
    0x90204,
    0x20024,
    0x2003a,
    0x2007d,
    0x2007c,
    0x20056,
    0x1004d,
    0x1014d,
    0x1104d,
    0x1114d,
    0x1204d,
    0x1214d,
    0x1304d,
    0x1314d,
    0x10049,
    0x10149,
    0x11049,
    0x11149,
    0x12049,
    0x12149,
    0x13049,
    0x13149,
    0x43,
    0x1043,
    0x2043,
    0x3043,
    0x4043,
    0x5043,
    0x20018,
    0x20075,
    0x20050,
    0x2009b,
    0x20008,
    0x20088,
    0x200b2,
    0x10043,
    0x10143,
    0x11043,
    0x11143,
    0x12043,
    0x12143,
    0x13043,
    0x13143,
    0x200fa,
    0x20019,
    0x200f0,
    0x200f1,
    0x200f2,
    0x200f3,
    0x200f4,
    0x200f5,
    0x200f6,
    0x200f7,
    0x20025,
    0x2002d,
    0x20021,
    0x2002c,
    0xd0000,
    0x90000,
    0x90001,
    0x90002,
    0x90003,
    0x90004,
    0x90005,
    0x90029,
    0x9002a,
    0x9002b,
    0x9002c,
    0x9002d,
    0x9002e,
    0x9002f,
    0x90030,
    0x90031,
    0x90032,
    0x90033,
    0x90034,
    0x90035,
    0x90036,
    0x90037,
    0x90038,
    0x90039,
    0x9003a,
    0x9003b,
    0x9003c,
    0x9003d,
    0x9003e,
    0x9003f,
    0x90040,
    0x90041,
    0x90042,
    0x90043,
    0x90044,
    0x90045,
    0x90046,
    0x90047,
    0x90048,
    0x90049,
    0x9004a,
    0x9004b,
    0x9004c,
    0x9004d,
    0x9004e,
    0x9004f,
    0x90050,
    0x90051,
    0x90052,
    0x90053,
    0x90054,
    0x90055,
    0x90056,
    0x90057,
    0x90058,
    0x90059,
    0x9005a,
    0x9005b,
    0x9005c,
    0x9005d,
    0x9005e,
    0x9005f,
    0x90060,
    0x90061,
    0x90062,
    0x90063,
    0x90064,
    0x90065,
    0x90066,
    0x90067,
    0x90068,
    0x90069,
    0x9006a,
    0x9006b,
    0x9006c,
    0x9006d,
    0x9006e,
    0x9006f,
    0x90070,
    0x90071,
    0x90072,
    0x90073,
    0x90074,
    0x90075,
    0x90076,
    0x90077,
    0x90078,
    0x90079,
    0x9007a,
    0x9007b,
    0x9007c,
    0x9007d,
    0x9007e,
    0x9007f,
    0x90080,
    0x90081,
    0x90082,
    0x90083,
    0x90084,
    0x90085,
    0x90086,
    0x90087,
    0x90088,
    0x90089,
    0x9008a,
    0x9008b,
    0x9008c,
    0x9008d,
    0x9008e,
    0x9008f,
    0x90090,
    0x90091,
    0x90092,
    0x90093,
    0x90094,
    0x90095,
    0x90096,
    0x90097,
    0x90098,
    0x90099,
    0x9009a,
    0x9009b,
    0x9009c,
    0x9009d,
    0x9009e,
    0x9009f,
    0x900a0,
    0x900a1,
    0x900a2,
    0x900a3,
    0x40000,
    0x40020,
    0x40040,
    0x40060,
    0x40001,
    0x40021,
    0x40041,
    0x40061,
    0x40002,
    0x40022,
    0x40042,
    0x40062,
    0x40003,
    0x40023,
    0x40043,
    0x40063,
    0x40004,
    0x40024,
    0x40044,
    0x40064,
    0x40005,
    0x40025,
    0x40045,
    0x40065,
    0x40006,
    0x40026,
    0x40046,
    0x40066,
    0x40007,
    0x40027,
    0x40047,
    0x40067,
    0x40008,
    0x40028,
    0x40048,
    0x40068,
    0x40009,
    0x40029,
    0x40049,
    0x40069,
    0x4000a,
    0x4002a,
    0x4004a,
    0x4006a,
    0x4000b,
    0x4002b,
    0x4004b,
    0x4006b,
    0x4000c,
    0x4002c,
    0x4004c,
    0x4006c,
    0x4000d,
    0x4002d,
    0x4004d,
    0x4006d,
    0x4000e,
    0x4002e,
    0x4004e,
    0x4006e,
    0x4000f,
    0x4002f,
    0x4004f,
    0x4006f,
    0x40010,
    0x40030,
    0x40050,
    0x40070,
    0x40011,
    0x40031,
    0x40051,
    0x40071,
    0x40012,
    0x40032,
    0x40052,
    0x40072,
    0x40013,
    0x40033,
    0x40053,
    0x40073,
    0x40014,
    0x40034,
    0x40054,
    0x40074,
    0x40015,
    0x40035,
    0x40055,
    0x40075,
    0x40016,
    0x40036,
    0x40056,
    0x40076,
    0x40017,
    0x40037,
    0x40057,
    0x40077,
    0x40018,
    0x40038,
    0x40058,
    0x40078,
    0x40019,
    0x40039,
    0x40059,
    0x40079,
    0x4001a,
    0x4003a,
    0x4005a,
    0x4007a,
    0x900a4,
    0x900a5,
    0x900a6,
    0x900a7,
    0x900a8,
    0x900a9,
    0x900aa,
    0x900ab,
    0x900ac,
    0x900ad,
    0x900ae,
    0x900af,
    0x900b0,
    0x900b1,
    0x900b2,
    0x900b3,
    0x900b4,
    0x900b5,
    0x900b6,
    0x900b7,
    0x900b8,
    0x900b9,
    0x900ba,
    0x900bb,
    0x900bc,
    0x900bd,
    0x900be,
    0x900bf,
    0x900c0,
    0x900c1,
    0x900c2,
    0x900c3,
    0x900c4,
    0x900c5,
    0x900c6,
    0x900c7,
    0x900c8,
    0x900c9,
    0x900ca,
    0x900cb,
    0x900cc,
    0x900cd,
    0x900ce,
    0x900cf,
    0x900d0,
    0x900d1,
    0x900d2,
    0x900d3,
    0x900d4,
    0x900d5,
    0x900d6,
    0x900d7,
    0x900d8,
    0x900d9,
    0x900da,
    0x900db,
    0x900dc,
    0x900dd,
    0x900de,
    0x900df,
    0x900e0,
    0x900e1,
    0x900e2,
    0x900e3,
    0x900e4,
    0x900e5,
    0x900e6,
    0x900e7,
    0x900e8,
    0x900e9,
    0x900ea,
    0x900eb,
    0x900ec,
    0x900ed,
    0x900ee,
    0x900ef,
    0x900f0,
    0x900f1,
    0x900f2,
    0x900f3,
    0x900f4,
    0x900f5,
    0x900f6,
    0x900f7,
    0x900f8,
    0x900f9,
    0x900fa,
    0x900fb,
    0x900fc,
    0x900fd,
    0x900fe,
    0x900ff,
    0x90100,
    0x90101,
    0x90102,
    0x90103,
    0x90104,
    0x90105,
    0x90106,
    0x90107,
    0x90108,
    0x90109,
    0x9010a,
    0x9010b,
    0x9010c,
    0x9010d,
    0x9010e,
    0x9010f,
    0x90110,
    0x90111,
    0x90112,
    0x90113,
    0x90114,
    0x90115,
    0x90116,
    0x90117,
    0x90118,
    0x90119,
    0x9011a,
    0x9011b,
    0x9011c,
    0x9011d,
    0x9011e,
    0x9011f,
    0x90120,
    0x90121,
    0x90122,
    0x90123,
    0x90124,
    0x90125,
    0x90126,
    0x90127,
    0x90128,
    0x90129,
    0x9012a,
    0x9012b,
    0x9012c,
    0x9012d,
    0x9012e,
    0x9012f,
    0x90130,
    0x90131,
    0x90132,
    0x90133,
    0x90134,
    0x90135,
    0x90136,
    0x90137,
    0x90138,
    0x90139,
    0x9013a,
    0x9013b,
    0x9013c,
    0x9013d,
    0x9013e,
    0x9013f,
    0x90140,
    0x90141,
    0x90142,
    0x90143,
    0x90144,
    0x90145,
    0x90146,
    0x90147,
    0x90148,
    0x90149,
    0x9014a,
    0x9014b,
    0x9014c,
    0x9014d,
    0x9014e,
    0x9014f,
    0x90150,
    0x90151,
    0x90152,
    0x90153,
    0x90154,
    0x90155,
    0x90156,
    0x90157,
    0x90158,
    0x90159,
    0x9015a,
    0x9015b,
    0x9015c,
    0x9015d,
    0x9015e,
    0x9015f,
    0x90160,
    0x90161,
    0x90162,
    0x90163,
    0x90164,
    0x90165,
    0x90166,
    0x90167,
    0x90168,
    0x90169,
    0x9016a,
    0x9016b,
    0x9016c,
    0x9016d,
    0x9016e,
    0x9016f,
    0x90170,
    0x90171,
    0x90172,
    0x90173,
    0x90174,
    0x90175,
    0x90176,
    0x90177,
    0x90178,
    0x90179,
    0x9017a,
    0x9017b,
    0x9017c,
    0x9017d,
    0x9017e,
    0x9017f,
    0x90180,
    0x90181,
    0x90006,
    0x90007,
    0x90008,
    0x90009,
    0x9000a,
    0x9000b,
    0xd00e7,
    0x90017,
    0x9001f,
    0x90026,
    0x400d0,
    0x400d1,
    0x400d2,
    0x400d3,
    0x400d4,
    0x400d5,
    0x400d6,
    0x400d7,
    0x200be,
    0x2000b,
    0x2000c,
    0x2000d,
    0x2000e,
    0x9000c,
    0x9000d,
    0x9000e,
    0x9000f,
    0x90010,
    0x90011,
    0x90012,
    0x90013,
    0x20010,
    0x20011,
    0x40080,
    0x40081,
    0x40082,
    0x40083,
    0x40084,
    0x40085,
    0x400fd,
    0x10011,
    0x10012,
    0x10013,
    0x10018,
    0x10002,
    0x100b2,
    0x101b4,
    0x102b4,
    0x103b4,
    0x104b4,
    0x105b4,
    0x106b4,
    0x107b4,
    0x108b4,
    0x11011,
    0x11012,
    0x11013,
    0x11018,
    0x11002,
    0x110b2,
    0x111b4,
    0x112b4,
    0x113b4,
    0x114b4,
    0x115b4,
    0x116b4,
    0x117b4,
    0x118b4,
    0x12011,
    0x12012,
    0x12013,
    0x12018,
    0x12002,
    0x120b2,
    0x121b4,
    0x122b4,
    0x123b4,
    0x124b4,
    0x125b4,
    0x126b4,
    0x127b4,
    0x128b4,
    0x13011,
    0x13012,
    0x13013,
    0x13018,
    0x13002,
    0x130b2,
    0x131b4,
    0x132b4,
    0x133b4,
    0x134b4,
    0x135b4,
    0x136b4,
    0x137b4,
    0x138b4,
    0x20089,
    0xc0080,
    0x200cb,
    0x10068,
    0x10069,
    0x10168,
    0x10169,
    0x10268,
    0x10269,
    0x10368,
    0x10369,
    0x10468,
    0x10469,
    0x10568,
    0x10569,
    0x10668,
    0x10669,
    0x10768,
    0x10769,
    0x10868,
    0x10869,
    0x100aa,
    0x10062,
    0x10001,
    0x100a0,
    0x100a1,
    0x100a2,
    0x100a3,
    0x100a4,
    0x100a5,
    0x100a6,
    0x100a7,
    0x11068,
    0x11069,
    0x11168,
    0x11169,
    0x11268,
    0x11269,
    0x11368,
    0x11369,
    0x11468,
    0x11469,
    0x11568,
    0x11569,
    0x11668,
    0x11669,
    0x11768,
    0x11769,
    0x11868,
    0x11869,
    0x110aa,
    0x11062,
    0x11001,
    0x110a0,
    0x110a1,
    0x110a2,
    0x110a3,
    0x110a4,
    0x110a5,
    0x110a6,
    0x110a7,
    0x12068,
    0x12069,
    0x12168,
    0x12169,
    0x12268,
    0x12269,
    0x12368,
    0x12369,
    0x12468,
    0x12469,
    0x12568,
    0x12569,
    0x12668,
    0x12669,
    0x12768,
    0x12769,
    0x12868,
    0x12869,
    0x120aa,
    0x12062,
    0x12001,
    0x120a0,
    0x120a1,
    0x120a2,
    0x120a3,
    0x120a4,
    0x120a5,
    0x120a6,
    0x120a7,
    0x13068,
    0x13069,
    0x13168,
    0x13169,
    0x13268,
    0x13269,
    0x13368,
    0x13369,
    0x13468,
    0x13469,
    0x13568,
    0x13569,
    0x13668,
    0x13669,
    0x13768,
    0x13769,
    0x13868,
    0x13869,
    0x130aa,
    0x13062,
    0x13001,
    0x130a0,
    0x130a1,
    0x130a2,
    0x130a3,
    0x130a4,
    0x130a5,
    0x130a6,
    0x130a7,
    0x80,  
    0x1080,
    0x2080,
    0x3080,
    0x4080,
    0x5080,
    0x10020,
    0x10080,
    0x10081,
    0x100d0,
    0x100d1,
    0x1008c,
    0x1008d,
    0x10180,
    0x10181,
    0x101d0,
    0x101d1,
    0x1018c,
    0x1018d,
    0x100c0,
    0x100c1,
    0x101c0,
    0x101c1,
    0x102c0,
    0x102c1,
    0x103c0,
    0x103c1,
    0x104c0,
    0x104c1,
    0x105c0,
    0x105c1,
    0x106c0,
    0x106c1,
    0x107c0,
    0x107c1,
    0x108c0,
    0x108c1,
    0x100ae,
    0x100af,
    0x11020,
    0x11080,
    0x11081,
    0x110d0,
    0x110d1,
    0x1108c,
    0x1108d,
    0x11180,
    0x11181,
    0x111d0,
    0x111d1,
    0x1118c,
    0x1118d,
    0x110c0,
    0x110c1,
    0x111c0,
    0x111c1,
    0x112c0,
    0x112c1,
    0x113c0,
    0x113c1,
    0x114c0,
    0x114c1,
    0x115c0,
    0x115c1,
    0x116c0,
    0x116c1,
    0x117c0,
    0x117c1,
    0x118c0,
    0x118c1,
    0x110ae,
    0x110af,
    0x12020,
    0x12080,
    0x12081,
    0x120d0,
    0x120d1,
    0x1208c,
    0x1208d,
    0x12180,
    0x12181,
    0x121d0,
    0x121d1,
    0x1218c,
    0x1218d,
    0x120c0,
    0x120c1,
    0x121c0,
    0x121c1,
    0x122c0,
    0x122c1,
    0x123c0,
    0x123c1,
    0x124c0,
    0x124c1,
    0x125c0,
    0x125c1,
    0x126c0,
    0x126c1,
    0x127c0,
    0x127c1,
    0x128c0,
    0x128c1,
    0x120ae,
    0x120af,
    0x13020,
    0x13080,
    0x13081,
    0x130d0,
    0x130d1,
    0x1308c,
    0x1308d,
    0x13180,
    0x13181,
    0x131d0,
    0x131d1,
    0x1318c,
    0x1318d,
    0x130c0,
    0x130c1,
    0x131c0,
    0x131c1,
    0x132c0,
    0x132c1,
    0x133c0,
    0x133c1,
    0x134c0,
    0x134c1,
    0x135c0,
    0x135c1,
    0x136c0,
    0x136c1,
    0x137c0,
    0x137c1,
    0x138c0,
    0x138c1,
    0x130ae,
    0x130af,
    0x90201,
    0x90202,
    0x90203,
    0x90205,
    0x90206,
    0x90207,
    0x90208,
    0x20020,
    0x20077,
    0x20072,
    0x20073,
    0x400c0,
    0x10040,
    0x10140,
    0x10240,
    0x10340,
    0x10440,
    0x10540,
    0x10640,
    0x10740,
    0x10840,
    0x11040,
    0x11140,
    0x11240,
    0x11340,
    0x11440,
    0x11540,
    0x11640,
    0x11740,
    0x11840,
    0x12040,
    0x12140,
    0x12240,
    0x12340,
    0x12440,
    0x12540,
    0x12640,
    0x12740,
    0x12840,
    0x13040,
    0x13140,
    0x13240,
    0x13340,
    0x13440,
    0x13540,
    0x13640,
    0x13740,
    0x13840,
};

void dwc_ddr_misc_regu_save(void)
{
    ddr_Regu_Config->misc_reg_num =  ARRAY_SIZE(MiscRegList);
    Reg_Misc_Addr_Val_t* misc_addr_t =  (Reg_Misc_Addr_Val_t*)((char*)ddr_Regu_Config +  64);
    for(int i = 0; i < ddr_Regu_Config->misc_reg_num; i++) {
        misc_addr_t[i].Address =  MiscRegList[i] & 0xffffffff;
        misc_addr_t[i].Value = rd(MiscRegList[i]);
#ifdef CONFIG_DDR_MSG
        DDR_DEBUG("misc_reg_addr_value:%d data:%d\n", misc_addr_t[i].Address, misc_addr_t[i].Value);
#endif
    }
}

int dwc_ddrphy_phyinit_regInterface(regInstr myRegInstr) {
    int regIndx=0;
    uint16_t data;
    ddr_phy_reg_wr(0xd0000, 0x0);
    ddr_phy_reg_wr(0xc0080, 0x3);

    uint32_t phy_reg_num = ARRAY_SIZE(RetRegList_addr);
    ddr_Regu_Config->phy_reg_num = phy_reg_num;
#ifdef CONFIG_DDR_DUAL_RANK
    ddr_Regu_Config->ddr_rank   =  2;
#else
    ddr_Regu_Config->ddr_rank   =  1;
#endif
    Reg_Phy_Addr_Val_t* phy_addr_t = (Reg_Phy_Addr_Val_t*)((char*)ddr_Regu_Config +  64 +  sizeof(Reg_Misc_Addr_Val_t) *  ARRAY_SIZE(MiscRegList));

#ifdef CONFIG_DDR_MSG
    DDR_DEBUG("pReg_Addr_Value %p\n", pReg_Addr_Value);
#endif
    if (myRegInstr == saveRegs)
    {
        // go through all the tracked registers, issue a register read and place
        // the result in the data structure for future recovery.
        for (regIndx = 0; regIndx < phy_reg_num; regIndx++)
        {
            data = ddr_phy0_reg_rd(RetRegList_addr[regIndx]);
            phy_addr_t[regIndx].Value0 = data;
            phy_addr_t[regIndx].Address = RetRegList_addr[regIndx];
        }
#ifndef CONFIG_DDR_H32_MODE
        for (regIndx = 0; regIndx < phy_reg_num; regIndx++)
        {
            data = ddr_phy1_reg_rd(RetRegList_addr[regIndx]);
            phy_addr_t[regIndx].Value1 = data;
        }
#endif
    }
    else if (myRegInstr == restoreRegs)
    {
        // write PHY registers based on Address, Data value pairs stores in
        // RetRegList
        ddr_phy0_reg_wr(0x20089, 0x1);
        for (regIndx = 0; regIndx < phy_reg_num; regIndx++)
        {
             ddr_phy0_reg_wr(phy_addr_t[regIndx].Address, phy_addr_t[regIndx].Value0);
        }

#ifndef CONFIG_DDR_H32_MODE
        ddr_phy1_reg_wr(0x20089, 0x1);
        for (regIndx = 0; regIndx < phy_reg_num; regIndx++)
        {
            ddr_phy1_reg_wr(phy_addr_t[regIndx].Address, phy_addr_t[regIndx].Value1);
        }
#endif
    }
    ddr_phy_reg_wr(0xc0080, 0x2);
    ddr_phy_reg_wr(0xd0000, 0x1);
    return 1;
}

void dwc_umctl_init_skip_traing(enum DDR_TYPE type, int rank_num, int speed, enum DDR_BITWIDTH bits)
{
  ddr_sysreg_wr(DDR_CFG0, 0x50);  // release apb presetn
  ddr_sysreg_wr(DDR_CFG0, 0x50);
  ddr_sysreg_wr(DDR_CFG0, 0x50);
  if (bits == 32) {
    ddr_sysreg_wr(DDR_CFG0, 0x52);
  }
  ctrl_init(rank_num, speed);
  addrmap(rank_num, bits);

  de_assert_other_reset_ddr(); //after this step, only PwrOk is staill low

  dq_pinmux(bits);


}

